<?php

namespace App\Api\Middleware;

use App\Common\Exception\ApiMessageException;
use App\Common\Model\Base\Token;
use App\Common\Util\ApiAuth;
use App\Common\Util\TP;
use Sc\Util\Tool;
use Sc\Util\Tool\JWT;
use think\Request;
use think\Response;

/**
 * Token设置
 *
 * Class ApiTokenSetMiddleware
 */
class ApiTokenSetMiddleware
{

    /**
     * @param Request  $request
     * @param \Closure $next
     *
     * @return Response
     * @throws \Exception
     */
    public function handle(Request $request, \Closure $next):Response
    {
        if (($token = $request->header('Authorization')) && str_starts_with($token, 'Bearer ')) {
            $token = preg_replace('/^Bearer /', '', $token);

            try {
                $tokenData = Tool::jwt(TP::config('jwt', []))->tokenVerify($token, false);

                ApiAuth::set($tokenData);
            } catch (\Exception) {}
        }

        /** @var Response $response */
        $response = $next($request);

        if (isset($response->getData()['code']) && $response->getData()['code'] === Tool\JWT::EXPIRE_CODE) {
            $response = \App\Common\Util\Response::json()->body(
                JWT::EXPIRE_CODE,
                "token refresh",
                $this->refreshToken($token)
            );
        }

        return $response;
    }

    /**
     * @param string $token
     *
     * @return array
     * @throws \Exception
     */
    private function refreshToken(string $token): array
    {
        /** @var Token $tokenModel */
        $tokenModel = Token::where('token_id', ApiAuth::get('jti'))->find();
        if (!$tokenModel) {
            $tokenModel = Token::create([
                "token_id" => ApiAuth::get('jti'),
                "version" => 0,
            ]);
        }

        // 验证版本
        if ($tokenModel->version > ApiAuth::get('jtiv', 0)) {
            throw new ApiMessageException("当前Token已失效", Tool\JWT::ERROR_CODE);
        }

        // 更新版本
        $tokenModel->version++;
        $tokenModel->save();

        $jwtConfig = TP::config('jwt', []);

        return Tool::jwt($jwtConfig)->selfRefresh($token);
    }
}